#pragma once
#include "../../Misc/UMask.h"
#include "GameScene.h"
#include "../../Math/Transform.h"
#include <string>
#include <entt/entt.hpp>

class Component;

struct IdComponent
{
	UMask id;
};

struct NameComponent
{
	std::string name;
};

class Entity
{
	friend class GameScene;

public:

	Entity() = default;
	Entity(const Entity& rhs) = default;
	Entity(Entity&& rhs) = default;

	Entity(entt::entity handle, GameScene* gameScene);

	template <typename T, typename... Args>
	T* AddComponent(Args&&... args)
	{
		if (HasComponent<T>())
		{
			assert(0);
		}
		T& component = mGameScene->GetRegistry().emplace<T>(mHandle, std::forward<Args>(args)...);
		// mComponents.push_back(&component);
		return &component;
	}

	template <typename T>
	T& GetComponent()
	{
		return mGameScene->GetRegistry().get<T>(mHandle);
	}

	template <typename T>
	T* TryGetComponent()
	{
		return mGameScene->GetRegistry().try_get<T>(mHandle);
	}

	template <typename T>
	bool HasComponent()
	{
		return mGameScene->GetRegistry().has<T>(mHandle);
	}

	template <typename T>
	void RemoveComponent()
	{
		T* component = mGameScene->GetRegistry().try_get<T>(mHandle);
		assert(component != nullptr);
		//for (uint32 i = 0; i < mComponents.size(); ++i)
		//{
		//	if (mComponents[i] == component)
		//	{
		//		mComponents.erase(mComponents.begin() + i);
		//		break;
		//	}
		//}
		mGameScene->GetRegistry().remove<T>(mHandle);
	}

	template <typename T>
	void TryRemoveComponent()
	{
		if (HasComponent<T>())
			RemoveComponent<T>();
	}

	entt::entity GetHandle() const;

	Transform& GetTransform();

	const Transform& GetTransform() const;

	uint64 GetId() const;

	const std::string& GetName();

protected:
	
	virtual void ReleaseResource();

	virtual void OnTick(float deltaTime) {};

private:

	void Tick(float deltaTime);

protected:

	entt::entity mHandle;

	GameScene* mGameScene;

	Transform mTransform;

	std::vector<Component*> mComponents;
};